package com.hzw.saas.service.rbac.service;

import java.util.List;
import java.util.Objects;
import javax.annotation.Resource;

import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper;
import com.baomidou.mybatisplus.extension.service.IService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.hzw.saas.api.rbac.IPermissionService;
import com.hzw.saas.api.rbac.bo.PermissionBO;
import com.hzw.saas.api.rbac.bo.PermissionStructBO;
import com.hzw.saas.api.rbac.bo.PermissionTreeBO;
import com.hzw.saas.api.rbac.constants.RbacConsts;
import com.hzw.saas.api.rbac.enums.PermSysEnum;
import com.hzw.saas.api.rbac.enums.PermTypeEnum;
import com.hzw.saas.api.rbac.query.PermissionAddQuery;
import com.hzw.saas.api.rbac.query.PermissionUpdateQuery;
import com.hzw.saas.common.config.util.AssertUtil;
import com.hzw.saas.common.util.MapperUtil;
import com.hzw.saas.common.util.SnowFlakeUtil;
import com.hzw.saas.service.rbac.IRolePermissionService;
import com.hzw.saas.service.rbac.mapper.PermissionMapper;
import com.hzw.saas.service.rbac.model.Permission;
import com.hzw.saas.service.rbac.model.RolePermission;
import com.hzw.saas.service.rbac.util.RbacUtil;
import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.StrUtil;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;

/**
 * @author zzl
 * @since 08/30/2021
 */
@Service
@Slf4j
@RequiredArgsConstructor
public class PermissionServiceImpl extends ServiceImpl<PermissionMapper, Permission> implements IPermissionService, IService<Permission> {

    @Resource
    private IRolePermissionService rolePermissionService;

    @Override
    public List<PermissionBO> list(Integer sys) {
        List<Permission> permissions = this.listDO(sys, null);
        List<PermissionBO> bos = MapperUtil.nf().mapAsList(permissions, PermissionBO.class);
        RbacUtil.assemblePermissionText(bos);
        return bos;
    }

    @Override
    public List<PermissionStructBO> listStruct(Integer sys) {
        LambdaQueryChainWrapper<Permission> queryWrapper = this.getQueryWrapper(sys, null);
        List<Permission> list = queryWrapper.select(Permission::getPid, Permission::getSupId).list();
        return MapperUtil.nf().mapAsList(list, PermissionStructBO.class);
    }

    @Override
    public List<PermissionTreeBO> listTree(Integer sys, String supId, Integer level, Integer... types) {
        // 初始化参数
        supId = this.initSupId(supId);
        // 获取所有权限
        List<Permission> entities = this.listDO(sys, null, types);
        List<PermissionTreeBO> sources = MapperUtil.nf().mapAsList(entities, PermissionTreeBO.class);
        // 组装说明文本
        RbacUtil.assemblePermissionText(sources);
        // 组装权限树
        return RbacUtil.assemblePermissionTrees(sources, supId, level);
    }

    @Override
    public PermissionBO save(PermissionAddQuery query) {
        // 校验参数
        PermSysEnum.assertValid(query.getSys());
        PermTypeEnum.assertValid(query.getType());
        // 初始化参数
        Permission entity = MapperUtil.nf().map(query, Permission.class);
        entity.setPid(SnowFlakeUtil.nextIdStr());
        entity.setSupId(this.initSupId(entity.getSupId()));
        assertSupValid(entity.getSupId());
        // 保存
        super.save(entity);
        return MapperUtil.nf().map(entity, PermissionBO.class);
    }

    @Override
    public boolean update(PermissionUpdateQuery query) {
        // 校验参数
        AssertUtil.assertThrow("PID不可为空", StrUtil.isBlank(query.getPid()));
        this.assertSupValid(query.getSupId());
        if (Objects.nonNull(query.getSys())) {
            PermSysEnum.assertValid(query.getSys());
        }
        // 更新
        Permission entity = MapperUtil.nf().map(query, Permission.class);
        return super.updateById(entity);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean delete(String pid) {
        Permission perm = super.getById(pid);
        AssertUtil.assertThrow("权限未找到", Objects.isNull(perm));
        // 获取所有子权限
        List<PermissionTreeBO> subPerms = this.listTree(perm.getSys(), perm.getPid(), -1);
        List<String> pids = RbacUtil.listAllPids(subPerms);
        pids.add(perm.getPid());
        // 删除权限
        super.lambdaUpdate().in(Permission::getPid, pids).remove();
        // 删除角色与权限的关联
        rolePermissionService.lambdaUpdate().in(RolePermission::getPermId, pids).remove();
        return true;
    }

    private List<Permission> listDO(Integer sys, String supId, Integer... types) {
        return this.getQueryWrapper(sys, supId, types).list();
    }

    private LambdaQueryChainWrapper<Permission> getQueryWrapper(Integer sys, String supId, Integer... types) {
        return super.lambdaQuery()
            .eq(Permission::getSys, sys)
            .eq(StrUtil.isNotBlank(supId), Permission::getSupId, supId)
            .in(ArrayUtil.isNotEmpty(types), Permission::getType, ListUtil.toList(types))
            .orderByAsc(Permission::getSeq)
            .orderByAsc(Permission::getCreateTime);
    }

    private String initSupId(String supId) {
        return StrUtil.isBlank(supId) ? RbacConsts.ROOT_PERMISSION_SUP_ID : supId;
    }

    private void assertSupValid(String supId) {
        if (Objects.nonNull(supId) && !Objects.equals(supId, RbacConsts.ROOT_PERMISSION_SUP_ID)) {
            Permission supPerm = super.getById(supId);
            AssertUtil.assertThrow("父级权限不存在: ".concat(supId), Objects.isNull(supPerm));
        }
    }

}
